/* Copyright (C) 2012  Chris Mueller <ruunsmail@googlemail.com>
 *
 * This file is part of the Liquid Programming Language
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "context.h"
#include "scanner.h"
#include "nodes.h"
#include "array.h"
#include "structures.h"
#include <stdlib.h>
#include <stdarg.h>

	
struct LqContext*
lq_context_new(const byte* source, const byte* filename)
{
	struct LqContext* context = malloc(sizeof(struct LqContext));
	struct LqFile* file = malloc(sizeof(struct LqFile));

	file->srcbegin = lq_cast(byte*, source);
	file->filename = filename;
	file->lines = lq_array_new(32, sizeof(struct LqLine));
	file->errors = 0;

	// Scanner //context->scanner = lq_scanner_new(file);
        context->stream = file->srcbegin;
        context->current = create_token(LQ_TOKEN_BOF, 0, 0, 0);
        context->buffer = lq_array_new(16, sizeof(byte));
        context->peek = lq_queue_new();
	context->file = file;

        // Parsing
        context->ast_root = 0;
	context->symbols = lq_stack_new();

	return context;
}


void
lq_context_free(struct LqContext* context)
{
	g_assert(context != 0);
	
        if(context->current != 0) {
                free(context->current);
        }

        lq_array_free(context->buffer);        
        lq_stack_free(context->symbols);
        lq_array_free(context->file->lines);
        lq_queue_free(context->peek, 0);

        // TODO: free ast_tree
        
	free(context->file);
	free(context);
}

void 
lq_notice(const byte* format, ...)
{
    va_list args;
    va_start(args, format);

    fprintf(stderr, "*** ");
    vfprintf(stderr, format, args);
    fprintf(stderr, "\n");

    va_end(args);
}


void 
lq_context_print_status(struct LqContext* context, FILE* out)
{
        fprintf(out, "File %s, lines %lu \n", context->file->filename, lq_array_size(context->file->lines));

        if(lq_array_size(context->file->lines) > 0) {
                struct LqLine*  line = lq_cast(struct LqLine*, lq_array_last(context->file->lines));

                fprintf(out, "  >> ");
                fwrite(line->begin, sizeof(byte), line->size, out);
                fprintf(out, "\n");
        }
        
        fprintf(out, "Symbolstack (size %lu)\n", lq_stack_size(context->symbols));
}


void
lq_error_at(struct LqFile* status, const byte* format, ...)
{
    g_assert(status != 0);

    va_list args;
    va_start(args, format);
    
    fprintf(stderr, "ERROR %s", status->filename);
    fprintf(stderr, " (line %lu): ", lq_array_size(status->lines));
    vfprintf(stderr, format, args);
    fprintf(stderr, "\n");

    status->errors++;

    va_end(args);
}


void
lq_error_at_line(struct LqFile* status, int line, const byte* format, ...)
{
    g_assert(status != 0);

    va_list args;
    va_start(args, format);
    
    fprintf(stderr, "ERROR %s", status->filename);

    if(line != LQ_NOLINE)
	    fprintf(stderr, " (line %d): ", line);
    else
	    fprintf(stderr, ": ");

    vfprintf(stderr, format, args);
    fprintf(stderr, "\n");

    status->errors++;

    va_end(args);
}


